#include <csignal>
#include <cstring>
#include "writer_buf.h"

namespace simple {
    WriterBuf::WriterBuf(int writeFd) : write_fd_(writeFd) {
        this->buff_data_ = new char[this->buff_size_];
    }

    WriterBuf::WriterBuf(int writeFd, int buffSize) : write_fd_(writeFd), buff_size_(buffSize) {
        this->buff_data_ = new char[this->buff_size_];
    }

    int WriterBuf::writeByte(char data) {
        if (this->autoFlush() == -1) {
            return -1;
        }
        this->buff_data_[this->write_index++] = data;
        return 1;
    }

    int WriterBuf::writeBytes(const std::vector<char> &data) {
        return this->writeBytes(data.data(), (int) data.size());
    }

    int WriterBuf::writeBytes(const void *ptr, int size) {
        int writeOffset = 0;
        while (writeOffset < size) {
            if (this->autoFlush() == -1) {
                return -1;
            }
            int bytes_written = size - writeOffset;
            if (bytes_written > this->capacity()) {
                bytes_written = this->capacity();
            }

            void *dest = this->buff_data_ + this->write_index;
            void *src = (char *) ptr + writeOffset;
            memcpy(dest, src, bytes_written);
            this->write_index += bytes_written;
            writeOffset += bytes_written;
        }
        return writeOffset;
    }

    int WriterBuf::writeString(const std::string &data) {
        return this->writeBytes(data.data(), (int) data.size());
    }

    int WriterBuf::autoFlush() {
        if (this->capacity() <= 0) {
            return this->flush();
        }
        return 0;
    }

    int WriterBuf::flush() {
        int offset = 0;
        while (offset < this->write_index) {
            int bytes_written = (int) write(this->write_fd_, this->buff_data_ + offset, this->write_index - offset);
            if (bytes_written == -1) {
                return -1;
            } else {
                offset += bytes_written;
            }
        }
        this->write_index = 0;
        return offset;
    }

    int WriterBuf::buffered() const {
        return this->write_index;
    }

    int WriterBuf::capacity() const {
        return this->buff_size_ - this->write_index;
    }

    int WriterBuf::size() const {
        return this->buff_size_;
    }

    void WriterBuf::reset() {
        this->write_fd_ = 0;
        this->write_index = 0;
    }

    void WriterBuf::close_() {
        this->flush();
        close(this->write_fd_);
    }
}